package com.lagou.edu.factory;

import com.lagou.edu.annotation.MyAutowired;
import com.lagou.edu.annotation.MyService;
import com.lagou.edu.annotation.MyTransactional;
import org.reflections.Reflections;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class BeanFactory {

    private static Map<String, Object> map = new HashMap<>();

    static {
        try {
            Reflections edus = new Reflections("com.lagou.edu");
            Set<Class<?>> clazzs = edus.getTypesAnnotatedWith(MyService.class);

            for (Class<?> clazz : clazzs) {
                Object object = clazz.getDeclaredConstructor().newInstance();

                MyService myService = clazz.getAnnotation(MyService.class);

                if (StringUtils.isEmpty(myService.value())) {
                    String[] names = clazz.getName().split("\\.");
                    map.put(names[names.length-1], object);
                } else {
                    map.put(myService.value(), object);
                }
            }

            for (Map.Entry<String, Object> entry : map.entrySet()) {
                Object obj = entry.getValue();
                Class clazz = obj.getClass();

                Field[] fields = clazz.getDeclaredFields();

                for (Field field : fields) {
                    if (!field.isAnnotationPresent(MyAutowired.class)
                        || !field.getAnnotation(MyAutowired.class).required()) {
                        continue;
                    }

                    String name = field.getName();
                    Method[] methods = clazz.getMethods();
                    for (int i = 0; i < methods.length; i++) {
                        Method method = methods[i];
                        if (method.getName() == null
                                || !method.getName().equalsIgnoreCase("set" + name)) {
                            continue;
                        }
                        method.invoke(obj, map.get(name));
                    }
                }

                if (clazz.isAnnotationPresent(MyTransactional.class)) {
                    ProxyFactory proxyFactory = (ProxyFactory) BeanFactory.getBean("proxyFactory");
                    Class[] face = clazz.getInterfaces();
                    if (face != null && face.length > 0) {
                        obj = proxyFactory.getJdkProxy(obj);
                    } else {
                        obj = proxyFactory.getCglibProxy(obj);
                    }
                }
                map.put(entry.getKey(), obj);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static Object getBean(String id) {
        return map.get(id);
    }
}
